package com.example.java_gobang.game;

import com.example.java_gobang.model.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

@Component
public class Matcher {
    private Queue<UserInfo> normalQueue = new ConcurrentLinkedQueue<>();
    private Queue<UserInfo> highQueue = new ConcurrentLinkedQueue<>();
    private Queue<UserInfo> veryHighQueue = new ConcurrentLinkedQueue<>();
    @Autowired
    private OnlineUserManager onlineUserManager;
    //按照分数将用户添加到不同段位的队列中
    @Autowired
    private ObjectMapper objectMapper;
    //房间管理器
    @Autowired
    private RoomManager roomManager;

    public void add(UserInfo userInfo) {
        if (userInfo.getScore() < 2000) {
            synchronized (normalQueue) {
                //三个线程互不干扰使用三把锁
                normalQueue.offer(userInfo);
                normalQueue.notify();
            }
            System.out.println("将" + userInfo.getUsername() + "加入普通匹配队列");
        } else if (userInfo.getScore() >= 2000 && userInfo.getScore() < 3000) {
            synchronized (highQueue) {
                highQueue.offer(userInfo);
                highQueue.notify();
            }
            System.out.println("将" + userInfo.getUsername() + "加入高手匹配队列");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.offer(userInfo);
                veryHighQueue.notify();
            }
            System.out.println("将" + userInfo.getUsername() + "加入大师匹配队列");
        }
    }

    //当玩家点击停止匹配时，将用户从队列中删除
    public void remove(UserInfo userInfo) {
        if (userInfo.getScore() < 2000) {
            synchronized (normalQueue) {
                normalQueue.remove(userInfo);
            }
            System.out.println("将" + userInfo.getUsername() + "移除普通匹配队列");
        } else if (userInfo.getScore() >= 2000 && userInfo.getScore() < 3000) {
            synchronized (highQueue) {
                highQueue.remove(userInfo);
            }
            System.out.println("将" + userInfo.getUsername() + "移除高手匹配队列");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.remove(userInfo);
            }
            System.out.println("将" + userInfo.getUsername() + "移除大师匹配队列");
        }
    }

    //创建扫描线程，对匹配队列不断扫描，知道有匹配的玩家
    public Matcher() {
        //对普通局队列扫描
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    handleMatcher(normalQueue);
                }
            }
        };
        t1.start();
        //对高端局队列扫描
        Thread t2 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    handleMatcher(highQueue);
                }
            }
        };
        t2.start();
        //对大师局队列扫描
        Thread t3 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    handleMatcher(veryHighQueue);
                }
            }
        };
        t3.start();
    }

    /**
     * 处理匹配
     *
     * @param matcherQueue
     */
    private void handleMatcher(Queue<UserInfo> matcherQueue) {
        synchronized (matcherQueue) {
            try {
                //1.判断人数是否够
                //当有新的玩家加入队列时就会唤醒阻塞
                //不过，可能有玩家加入后队列人数依然小于2
                //所以这里要使用while进行再次判断
                while (matcherQueue.size() < 2) {
                    //当有玩家加入后等待解除
                    matcherQueue.wait();
                }
                //2.获得两个玩家信息
                System.out.println("匹配成功");
                UserInfo player1 = matcherQueue.poll();
                UserInfo player2 = matcherQueue.poll();
                System.out.println("玩家1: " + player1.getUsername());
                System.out.println("玩家2: " + player2.getUsername());
                //3.获取玩家websocket会话，告诉玩家排到了
                WebSocketSession session1 = onlineUserManager.getFromRoom(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromRoom(player2.getUserId());
                if (session1 == null) {
                    //如果玩家1不在线就把玩家二重新放入队列
                    matcherQueue.offer(player2);
                    return;
                }
                if (session2 == null) {
                    matcherQueue.offer(player1);
                    return;
                }
                //这个情况正常不会出现
                //因为前面已经做出了两个处理
                //1.当玩家下线时，将玩家退出匹配队列
                //2.禁止多开
                if (session1 == session2) {
                    //如果匹配到的玩家一致，就将第一个从新放入队列中
                    matcherQueue.offer(player1);
                    return;
                }
                //3.添加两名玩家的游戏房间
                Room room = new Room();
                //这里并没有真正将两名玩家加入到房间中，Room里的id还没设置
                //而是创建一个游戏房间，通过玩家id可以找到对应要加入的游戏房间
                roomManager.addRoom(room,player1.getUserId(),player2.getUserId());
                //4.返回响应信息
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                String json1 = objectMapper.writeValueAsString(response1);
                session1.sendMessage(new TextMessage(json1));

                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                String json2 = objectMapper.writeValueAsString(response2);
                session2.sendMessage(new TextMessage(json2));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
